import 'dart:async';

/**
 * @Description: 消息队列
 * @Author: 下雨了
 * @CreateDate: 2022-05-30 9:38
 * @UpdateUser: 更新者
 * @UpdateDate:  2022-05-30 9:38
 * @UpdateRemark: 更新说明
 * @Version: 1.0
 */
///
class QueueUtils {
  // 私有构造函数
  QueueUtils._internal() {
    // 初始化
  }

  // 保存单例
  static final QueueUtils _queueUtils = QueueUtils._internal();

  // 工厂构造函数
  factory QueueUtils() => _queueUtils;

  /// 用map key存储多个QueueUtil单例,目的是隔离多个类型队列任务互不干扰
  /// Use map key to store multiple QueueUtil singletons, the purpose is to isolate multiple types of queue tasks without interfering with each other
  static Map<String, QueueUtils> _instance = Map<String, QueueUtils>();

  static QueueUtils? get(String key) {
    if (_instance[key] == null) {
      _instance[key] = QueueUtils._internal();
    }
    return _instance[key];
  }

  List<TaskInfo> _taskList = [];
  bool _isTaskRunning = false; // 任务 是否 在运行
  int _mId = 0;
  bool _isCancelQueue = false; // 是否 取消队列

  /// 获取任务列表
  List<TaskInfo> getTaskList() {
    return _taskList;
  }

  /// 添加任务
  Future<TaskInfo> addTask(String name, {required Function doSomething, Function? onError}) {
    _isCancelQueue = false;
    _mId++;
    TaskInfo taskInfo = TaskInfo(_mId, name, doSomething);

    /// 创建future
    Completer<TaskInfo> taskCompleter = Completer<TaskInfo>();

    /// 创建当前任务stream
    StreamController<TaskInfo> streamController = new StreamController();
    taskInfo.controller = streamController;

    /// 添加到任务队列
    _taskList.add(taskInfo);

    /// 当前任务的stream添加监听
    /// stream 从Stream的另一端弹出数据
    streamController.stream.listen(
      (TaskInfo completeTaskInfo) {
        if (completeTaskInfo.id == taskInfo.id) {
          taskCompleter.complete(completeTaskInfo);
          streamController.close();
        }
      },
      onError: (error) {
        onError?.call();
        streamController.close();
      }
    );

    /// 触发任务
    _doTask();

    return taskCompleter.future;
  }

  /// 取消任务
  void cancelTask() {
    _taskList = [];
    _isCancelQueue = true;
    _mId = 0;
    _isTaskRunning = false;
  }

  /// 做任务
  _doTask() async {
    if (_isTaskRunning) return;
    if (_taskList.isEmpty) return;

    /// 取任务
    TaskInfo taskInfo = _taskList[0];
    _isTaskRunning = true;

    try {
      /// 模拟执行任务
      await taskInfo.doSomething?.call();

      /// sink 从Stream中的一端插入数据
      taskInfo.controller?.sink.add(taskInfo);

      if (_isCancelQueue) return;
    } catch (e) {
      print(e);
      /// sink 向Stream中添加 error
      taskInfo.controller?.sink.addError(e);
    } finally {
      /// 出队列
      _taskList.removeAt(0);
      _isTaskRunning = false;

      /// 递归执行任务
      _doTask();
    }
  }
}

/// 任务信息
class TaskInfo {
  int id; // 任务唯一标识
  String name; // 任务名称
  Function? doSomething;
  StreamController<TaskInfo>? controller;

  TaskInfo(this.id, this.name, this.doSomething, {this.controller});
}

main() {
  /// 将任务添加到队列
  print("加入队列-net, taskNo: 1");
  QueueUtils.get("net")?.addTask("任务1", doSomething: () {
    // return 此处必须有 不然无效
    return _doFuture("net", 1);
  });
  print("加入队列-net, taskNo: 2");
  QueueUtils.get("net")?.addTask("任务2", doSomething: () {
    return _doFuture("net", 2);
  });
  print("加入队列-local, taskNo: 3");
  QueueUtils.get("local")?.addTask("任务3",doSomething: () {
    return _doFuture("local", 3);
  });

  /// 取消队列任务
  /// QueueUtils.get("net").cancelTask();


}

Future _doFuture(String queueName, int taskNo) {
  return Future.delayed(Duration(seconds: 2), () {
    print("任务完成  queueName: $queueName, taskNo: $taskNo");
  });
}
